Skip to content

fix(desktop,mcp): honor device-local agent preset overrides in MCP-launched sessions - #5889

Closed
jeremy wants to merge 2 commits into
ParadevAI:mainfrom
jeremy:honor-device-agent-presets-in-mcp-launches
Closed

jeremy wants to merge 2 commits into
ParadevAI:mainfrom
jeremy:honor-device-agent-presets-in-mcp-launches

Conversation

@jeremy

@jeremy jeremy commented Jul 22, 2026 •

Copy link
Copy Markdown
Contributor

Problem

In Superset, a user can customize each agent's launch command in the desktop UI (e.g. set claude to claude --permission-mode plan --dangerously-skip-permissions). The desktop UI honors these overrides, but MCP-launched sessions ignore them — an agent started via start_agent_session / start_agent_session_with_prompt always ran the hardcoded builtin command, so the user's plan-mode / custom flags never took effect.

Root cause: user overrides (agentPresetOverrides, agentCustomDefinitions) are stored device-local in SQLite (packages/local-db settings). They are not in Postgres, so the cloud MCP server can't read them and bakes the command from builtins only. The device command-watcher trusts that baked command verbatim, even though the device has the presets via settings.getAgentPresets.

Approach — device re-resolves; additive & rolling-update-safe

Overrides only exist on the device, so the effective command can only be resolved there. The change is additive over the server→device agent_commands queue so it stays compatible across rolling updates:

  • The MCP server keeps sending the baked builtin command as a fallback, and now additionally carries what the device needs to re-resolve: the raw prompt (prompt launches) and taskPromptContent/taskPromptFileName (task launches, matching how UI task launches already behave).
  • A new device prefers local re-resolution from the user's presets via the existing resolveAgentConfigs path; it falls back to the baked command when the presets, a matching enabled terminal config, or the prompt fields are absent.
  • An old device ignores the new fields and runs the baked command (unchanged). A new device tolerates old-server requests that lack the fields.

Only the command string is overwritten — server-provided name/paneId/files/taskPromptContent stay authoritative. Chat/superset launches are never touched.

Changes

  • packages/shared/src/agent-launch.ts — add optional prompt to terminalLaunchConfigSchema.
  • packages/mcp/.../start-agent-session/shared.ts — prompt launch carries prompt; task launch switched to the UI file-command shape (buildAgentFileCommand + taskPromptContent + taskPromptFileName).
  • .../useCommandWatcher/tools/types.ts — add optional getResolvedAgentConfigsById getter to ToolContext.
  • .../useCommandWatcher/useCommandWatcher.ts — wire settings.getAgentPresets → memoized indexResolvedAgentConfigs → the toolContext getter.
  • .../useCommandWatcher/tools/start-agent-session.ts — resolveDeviceLocalCommand re-resolves the terminal command from local presets (task → file command, prompt → prompt command), falling back to the baked command in every gap.

Tests

  • New device test (tools/start-agent-session.test.ts): override prompt/task launches use the overridden command; authoritative fields preserved; baked-command fallback for disabled config, missing config, absent resolver getter, and old-server requests; chat/superset untouched.
  • MCP test: prompt request carries terminal.prompt; task request uses file command + prompt content/filename.
  • Shared schema round-trip test for prompt.
  • Full suites green (shared 697, mcp 7, AgentHooks 17); desktop tsc --noEmit, shared/mcp typechecks, and biome all clean.

Out of scope (separate follow-up)

The cwd/worktree-readiness spawn race — create_workspace returns before the worktree dir exists (initializeWorkspaceWorktree is fire-and-forget), so a PTY spawned immediately after can die. It's a different code path (main-process init vs renderer command resolution) and should ship as its own change.


Summary by cubic

MCP-launched agent sessions now honor device-local agent preset overrides from the desktop UI. Commands are resolved on the device using local presets with baked fallbacks, and MCP command processing is deferred until presets load to avoid a startup race that could ignore overrides.

  • Bug Fixes
    • Server continues sending a baked builtin command and now also includes terminal.prompt or taskPromptContent/taskPromptFileName; the device prefers local re-resolution and falls back when data or presets are missing (rolling-update safe).
    • Added optional prompt to terminalLaunchConfigSchema in @superset/shared to carry raw prompts for device-side resolution.
    • Desktop command watcher indexes presets, defers MCP command processing until the presets query settles, and exposes getResolvedAgentConfigsById; only terminal.command is replaced, while name/paneId/files remain authoritative. Chat/superset launches are untouched.
    • Tests cover override application, fallbacks for old servers/devices, and schema round-trips.

Written for commit 4ffddd2. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • New Features

    • Terminal-based agent sessions now use the latest device-local agent settings when available.
    • Prompt and task launches preserve the information needed to rebuild commands locally.
    • Task sessions now reference their associated prompt files for more reliable launches.
    • Older devices and unsupported configurations continue using the original launch command.
  • Tests

    • Added coverage for prompt, task, chat, fallback, and compatibility scenarios.

…unched sessions

MCP-launched agent sessions ran the hardcoded builtin command (e.g.
`claude --dangerously-skip-permissions`) instead of the user's
UI-configured launch command. Agent preset overrides live only in the
device SQLite settings, so the cloud MCP server can't read them and bakes
the command from builtins alone.

Resolve the effective command on the device, where the presets exist. The
MCP server keeps sending the baked builtin command as a fallback and now
also carries what the device needs to re-resolve: the raw `prompt` for
prompt launches, and `taskPromptContent`/`taskPromptFileName` for task
launches. A new device re-resolves from the user's presets via the
existing `resolveAgentConfigs` path; it falls back to the baked command
whenever the presets, a matching enabled terminal config, or the prompt
fields are absent.

The change is additive over the server->device agent_commands queue, so it
is safe across rolling updates: old devices ignore the new fields and run
the baked command, and new devices tolerate old-server requests that lack
them.

Out of scope: the cwd/worktree-readiness spawn race in create_workspace
(worktree dir may not exist when a PTY spawns immediately after). Different
code path; separate follow-up.
Copilot AI review requested due to automatic review settings July 22, 2026 21:12
@coderabbitai

coderabbitai Bot commented Jul 22, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Terminal launch requests now preserve prompt and task-file metadata. Desktop command execution uses resolved device-local agent presets to rebuild eligible terminal commands while retaining baked-command fallbacks and leaving chat launches unchanged.

Changes

Agent command resolution

Layer / File(s) Summary
Launch request metadata and construction
packages/shared/src/agent-launch.ts, packages/mcp/src/tools/devices/start-agent-session/..., packages/shared/src/agent-launch.test.ts
Terminal schemas and MCP launch builders carry prompt or task prompt-file metadata alongside baked commands, with normalization coverage.
Desktop preset lookup and command rebuilding
apps/desktop/src/renderer/routes/_authenticated/components/AgentHooks/hooks/useCommandWatcher/...
The command watcher indexes resolved agent configurations and delays processing until presets are fetched; terminal launches rebuild commands from eligible local presets while preserving fallback behavior.
Command resolution tests
apps/desktop/src/renderer/routes/_authenticated/components/AgentHooks/hooks/useCommandWatcher/tools/start-agent-session.test.ts
Tests cover prompt and task overrides, preserved terminal fields, fallback cases, absent resolver support, and unchanged chat launches.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant MCPStartAgentSession
  participant SharedLaunchSchema
  participant useCommandWatcher
  participant startAgentSession
  participant AgentSessionOrchestrator

  MCPStartAgentSession->>SharedLaunchSchema: build terminal request with prompt or task-file metadata
  SharedLaunchSchema->>useCommandWatcher: normalized launch request
  useCommandWatcher->>startAgentSession: execute with resolved agent-config lookup
  startAgentSession->>AgentSessionOrchestrator: launch rebuilt local command or baked fallback
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title is concise, conventional-commit formatted, and accurately summarizes the main change to honor device-local agent preset overrides.
Description check ✅ Passed The description is detailed and covers the problem, approach, changes, tests, and out-of-scope notes, matching the template's intent.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes a mismatch between desktop UI agent launching and MCP-launched agent sessions by ensuring device-local agent preset overrides (stored in SQLite) are honored when sessions are initiated via MCP. It does this by having the device re-resolve the effective terminal command from its local presets, while keeping the server-provided baked command as a safe fallback for rolling upgrades.

Changes:

  • Extended the shared terminal launch schema to optionally carry the raw prompt (in addition to the baked command) so the device can re-resolve using local presets.
  • Updated MCP start-agent-session request building to include prompt/task prompt fields needed for device-side re-resolution (task launches now follow the same “file command + prompt content/filename” shape as the UI).
  • Updated the desktop command-watcher tool context and start-agent-session tool to re-resolve terminal commands via resolveAgentConfigs when local presets are available, with comprehensive fallback behavior covered by tests.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated no comments.

Show a summary per file
File Description
packages/shared/src/agent-launch.ts Adds optional terminal.prompt to support device-side command re-resolution.
packages/shared/src/agent-launch.test.ts Adds schema round-trip test coverage for the new terminal.prompt field.
packages/mcp/src/tools/devices/start-agent-session/start-agent-session.test.ts Updates MCP tests to assert task prompt fields/file command shape and prompt-carrying behavior.
packages/mcp/src/tools/devices/start-agent-session/shared.ts Switches MCP task launches to file-command shape and includes prompt/task prompt fields for device re-resolution.
apps/desktop/src/renderer/routes/_authenticated/components/AgentHooks/hooks/useCommandWatcher/useCommandWatcher.ts Wires settings.getAgentPresets into a memoized indexed map exposed via tool context.
apps/desktop/src/renderer/routes/_authenticated/components/AgentHooks/hooks/useCommandWatcher/tools/types.ts Extends ToolContext with optional getResolvedAgentConfigsById for backwards compatibility.
apps/desktop/src/renderer/routes/_authenticated/components/AgentHooks/hooks/useCommandWatcher/tools/start-agent-session.ts Implements device-local command re-resolution for terminal launches, preserving server-authoritative fields and falling back safely.
apps/desktop/src/renderer/routes/_authenticated/components/AgentHooks/hooks/useCommandWatcher/tools/start-agent-session.test.ts Adds device-side tests validating override behavior and all intended fallback cases.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9a9e60a265

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
packages/mcp/src/tools/devices/start-agent-session/shared.ts (1)

139-183: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy lift

Duplicate buildTaskLaunchRequest implementation across packages.

This function mirrors buildTaskLaunchRequest in packages/shared/src/agent-launch.ts (lines 205-257): both compute taskPromptFileName, call buildAgentFileCommand/buildAgentTaskPrompt, and populate the same terminal.{name,taskPromptContent,taskPromptFileName} triplet. This PR had to touch both to add the file-based approach and prompt metadata — a sign the duplication will keep requiring synchronized edits (and risks drifting silently if one is missed).

Consider extracting the shared terminal-request-building logic into @superset/shared (parameterized over TaskInput/TaskRecord) so both callers converge on one implementation.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/mcp/src/tools/devices/start-agent-session/shared.ts` around lines
139 - 183, The terminal launch construction in buildTaskLaunchRequest is
duplicated with the implementation in the shared agent-launch module. Extract
the common terminal-request-building logic into `@superset/shared`, parameterized
to accept the relevant TaskInput/TaskRecord shape, and update both callers to
reuse it while preserving the existing superset chat branch and request fields.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@packages/mcp/src/tools/devices/start-agent-session/shared.ts`:
- Around line 139-183: The terminal launch construction in
buildTaskLaunchRequest is duplicated with the implementation in the shared
agent-launch module. Extract the common terminal-request-building logic into
`@superset/shared`, parameterized to accept the relevant TaskInput/TaskRecord
shape, and update both callers to reuse it while preserving the existing
superset chat branch and request fields.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 219182b2-d43b-4b9c-bbeb-b5ecfd24ee04

📥 Commits

Reviewing files that changed from the base of the PR and between 63909c1 and 9a9e60a.

📒 Files selected for processing (8)
  • apps/desktop/src/renderer/routes/_authenticated/components/AgentHooks/hooks/useCommandWatcher/tools/start-agent-session.test.ts
  • apps/desktop/src/renderer/routes/_authenticated/components/AgentHooks/hooks/useCommandWatcher/tools/start-agent-session.ts
  • apps/desktop/src/renderer/routes/_authenticated/components/AgentHooks/hooks/useCommandWatcher/tools/types.ts
  • apps/desktop/src/renderer/routes/_authenticated/components/AgentHooks/hooks/useCommandWatcher/useCommandWatcher.ts
  • packages/mcp/src/tools/devices/start-agent-session/shared.ts
  • packages/mcp/src/tools/devices/start-agent-session/start-agent-session.test.ts
  • packages/shared/src/agent-launch.test.ts
  • packages/shared/src/agent-launch.ts

The command-watcher's pendingCommands query can emit before
settings.getAgentPresets resolves. In that window the resolved-config index
was an empty map, so resolveDeviceLocalCommand found no config, fell back to
the server-baked command, and the watcher marked the command handled — the
launch was never re-resolved once the overrides arrived, intermittently
ignoring device-local agent command overrides on startup.

Gate shouldWatch on the presets query having settled, and return undefined
(not an empty index) while it is still loading so the loading state is never
mistaken for "no override".
@jeremy

jeremy commented Jul 22, 2026

Copy link
Copy Markdown
Contributor Author

Re: CodeRabbit nitpick on duplicate buildTaskLaunchRequest (shared vs mcp) — deferring as out of scope for this fix. The two functions only converge on the terminal-command triplet; they still diverge on input type (TaskInput vs the DB-derived TaskRecord), source, paneId/autoExecute, and the superset chat branch (DEFAULT_CHAT_TASK_PROMPT_TEMPLATE + taskSlug vs buildAgentTaskPrompt). Extracting a shared builder would touch the UI launch path that packages/shared feeds, which is broader than this bug fix should carry. Worth a dedicated follow-up rather than folding into this PR.

@Kitenite

Copy link
Copy Markdown
Member

Closing: main already ships this. v1 MCP server removed in 0290c46 (#6082); target files gone. Thanks for the PR; if you think the shipped version misses a case, open an issue and link this.

@Kitenite Kitenite closed this Aug 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants